[BITS 16]
[ORG 0x20200]

	cli	
	mov ax, 0x2000
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0x200
	;sti
;Выведем приветствие на экран
	;hlt
	;jmp $	
	mov si, boot1_loaded
	call puts
	;hlt
	;jmp	$ 
;++++++Включение линии A20+++++++++++++++++++++++++
	mov	al,00010001b
	out	0x20,al
	mov	al,0x20
	out	0x21,al
	mov	al,00000100b
	out	0x21,al
	mov	al,00000001b
	out 0x21,al
;+++++++++++++++++++++++++++++++	

;Строим карту памяти (доделать на случай если нет е820 инт 0х15)
	call e820call
		
	;hlt
	;jmp $
;##########################
	;cli
;Загрузим в gdt структуру описывающую глобальную таблицу дескрипторов
	lgdt	[gdt_reg]
;Включим защищенный режим
	mov     eax, ksetup
    call    puthexd
    call    putend
    
    mov     eax, kernel
    call    puthexd
    call    putend
    
    mov     eax, kernel_init_s
    call    puthexd
    call    putend
    
    hlt
	jmp $
	
    mov	eax, cr0
	inc	eax
	mov	cr0, eax
	
;Прыжок в защищенный режим
;0x8 - сегмент кода
	db 0x66, 0xea	;Сигнатура команды jmp
	dd pmode
	dw 0x8
	;jmp	0x8:pmode	
test1: jmp $ ;эта строка не достижима
	
	

;Печатает число в al в шестнадцатиричном коде
puthex:
	pushad
	cmp al, 0xA
;если число в al меньше 10
	jc .litle
	add	al, 0x37
	jmp puthex.putc
.litle:
	add al, 0x30
.putc:
	mov	ah, 0x0e
	int	0x10	
	popad
	ret
;Печатает число находящееся в al в шестнадцатиричном коде
puthexb:
	pushad
	mov	bl, al
	shr	al, 4
	call puthex
	mov	al, bl
	and	al, 0xF
	call puthex
	popad
	ret
;Печатает число находящееся в ax в шестнадцатиричном коде
puthexw:
	pushad
	mov bl, al
	mov al, ah
	call puthexb
	mov	al, bl
	call puthexb
	popad
	ret
;Печатает число в eax в шестнадцатиричном коде
puthexd:
	pushad
	mov ebx, eax
	shr eax, 16
	call puthexw
	mov	eax, ebx
	call puthexw
	popad
	ret

putend:
	push ax
	mov	al, 0xA
	mov ah, 0xe
	int 0x10
	mov al, 0xD
	mov ah, 0xe
	int 0x10
	pop ax
	ret
	
putchard:
	pushad
	mov ebx, eax
	shr eax, 24
	mov ah, 0xe
	int 0x10
	mov eax, ebx
	shr eax, 16
	mov	ah, 0xe
	int 0x10
	mov eax, ebx
	shr ax, 8
	mov ah, 0xe
	int 0x10
	mov eax, ebx
	mov	ah, 0xe
	int 0x10
	popad
	ret

putchar:
	mov ah, 0xe
	int 0x10
	ret

printregs:
	pushad
	push eax
	mov al, "A"
	call putchar
	mov al, "X"
	call putchar
	mov al, ":"
	call putchar
	pop eax
	call puthexd
	mov al, " "
	call putchar
	mov al, "B"
	call putchar
	mov al, "X"
	call putchar
	mov al, ":"
	call putchar
	mov eax, ebx
	call puthexd
	mov al, " "
	call putchar
	mov al, "C"
	call putchar
	mov al, "X"
	call putchar
	mov al, ":"
	call putchar
	mov eax, ecx
	call puthexd
	mov al, " "
	call putchar
	mov al, "D"
	call putchar
	mov al, "X"
	call putchar
	mov al, ":"
	call putchar
	mov eax, edx
	call puthexd
	call putend
	
	popad
	ret
	
puterror:
	mov	si, acpi_err_cf
	call puts
	hlt
	jmp $

;Определение объема оперативной памяти при помощи ACPI int15h E820h
e820call:
	mov ebx, 0	;начальное значение в ebx должно быть 0
	mov esi, 0	;счетчик обращений к прерыванию
.loop:	
;вычисляем адрес структуры в которую писать acpi_mem + acpi_mem_size * 24
	mov eax, [acpi_mem_size]
	mov ecx, 24
	mul	ecx
	add eax, acpi_mem
	mov edi, eax ;заносим адрес структуры в edi
	call puthexd
	mov al, " "
	call putchar
	mov eax, acpi_mem
	call puthexd
	call putend
	
	;or	ebx, 0x534D
	mov eax, 0xe820	;в eax номер функции
	mov	ecx, 24	;в ecx размер структуры адрес которой вычислили
	mov	edx, "PAMS"
	call printregs
	int 0x15
	call printregs
	jc short .error
	;call putchard
	;call putend
	cmp	eax, "PAMS"
	jnz short .error
	mov	eax, [acpi_mem_size]
	inc eax
	mov [acpi_mem_size], eax
	call puthexb
	call putend
	call putend
	
	test ebx, ebx
	jz short .quit
	cmp esi, 10
	je	short .quit
	inc esi
	jmp short .loop
.error:
	mov	si, acpi_err_smap
	call puts
	hlt
	jmp $
	ret
.quit:
	mov si, acpi_ok
	call puts
	ret
	
	
	
;Защищенный режим
[BITS 32]
pmode:
	
;Загрузим в сегментные регистры (кроме cs) селектор сегмента данных
	mov	ax, 16
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
	mov	gs, ax
;Загрузим в ss селектор сегмента стека
	mov	ss, ax
	mov	esp, 0x400000

;Теперь перенесем код инициализации в положенное ему место
	cld
	mov esi, ksetup
	mov edi, 0x100000
	mov ecx, (kernel - ksetup)
	rep movsb
	
;Сохраним параметры ядра, для кода инициализации (ksetup)
	push dword [ram_fs_size]
	push ram_fs
	push dword [acpi_mem_size]
	push acpi_mem
	push kernel_init_s
;Переходим к коду инициализации ядра. От туда не возвращаемся.
	;cli
	;hlt
	;jmp $
	jmp 0x100000
;Этот код недостижим
	hlt	
	jmp	$

;Функция выводит строку в SI на экран
puts:
	pusha
.loop:
	lodsb
	test al, al
	jz .quit
	mov ah, 0x0e
	int 0x10
	jmp short .loop
.quit:
	;mov al, 0x31
	;mov ah, 0x0e
	;int 0x10
	;hlt
	;jmp	$
	popa
	ret

testf:
	pushad
	popad
	ret

gdt:
;Первый дескриптор пустой
dw 0, 0, 0, 0
;Дескриптор кода на весь диапазон адресов
db 0xff
db 0xff
db 0x00
db 0x00
db 0x00
db 10011010b
db 11001111b
db 0x00

;Дескриптор данных
db 0xff
db 0xff
db 0x00
db 0x00
db 0x00
db 10010010b
db 11001111b
db 0x00

;Дескриптор стека
;00FFFFFF	предел
;00FFFFFF	база
db 0x00
db 0x00
db 0x00
db 0x00
db 0x00
db 10010110b
db 11000000b
db 0x00


gdt_reg:
dw 0x2000
dd gdt
;dw 0x9



boot1_loaded:	db	"BOOT1 is loaded", 0x0a, 0x0d, 0

acpi:	db	"Memory: ", 0x0a, 0x0d, 0

acpi_err_cf:	db	"ACPI error CF", 0xa, 0xd, 0

acpi_err_smap:	db	"ACPI error SMAP", 0xa, 0xd, 0

acpi_ok:	db	"ACPI OK", 0xa, 0xd, 0

ram_fs:
incbin "../../../../ramfs"
ram_fs_size:
dd	ram_fs_size - ram_fs

ram_addr:
dd  ram_fs
ram_size_addr:
dd  ram_fs_size

ksetup:
incbin	"setup"

kernel:
incbin "../../../../sirena"



kernel_init_s:
dd	kernel_init_s - kernel
dd	kernel
dd	kernel_init_s
dd	0xABCD
acpi_mem_size:
dd	0x0
acpi_mem:
dd	0x0

